package cn.zhangfusheng.elasticsearch.repository;

import cn.zhangfusheng.elasticsearch.exception.GlobalSystemException;
import cn.zhangfusheng.elasticsearch.model.page.PageRequest;
import cn.zhangfusheng.elasticsearch.model.page.PageResponse;
import cn.zhangfusheng.elasticsearch.scan.ElasticSearchEntityRepositoryDetail;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.search.SearchHit;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Optional;

/**
 * es 查询api
 * @author fusheng.zhang
 * @date 2022-04-21 19:20:13
 */
public interface DefaultElasticSearchQueryRepository<T> extends DefaultRepository<T> {

    @Override
    default Optional<T> findById(String primaryId) {
        return this.findById(primaryId, null);
    }

    @Override
    default Optional<T> findById(String primaryId, String routing) {
        ElasticSearchEntityRepositoryDetail entityRepositoryDetail = entityRepositoryDetail();
        String indexName = entityRepositoryDetail.getSearchIndex();
        GetResponse getResponse =
                elasticSearchRestTemplate().get(indexName, routing, primaryId, null, null);
        T t = entityRepositoryDetail.parseToEntity(getResponse.getSource());
        return Optional.ofNullable(t);
    }

    @Override
    default <Q, R> Optional<R> findOne(Q q) {
        ElasticSearchEntityRepositoryDetail elasticSearchEntityRepositoryDetail = entityRepositoryDetail();
        String routing = elasticSearchEntityRepositoryDetail.routing(q);
        List<SearchHit> searchHits = elasticSearchRestTemplate().search(new Object[]{q}, routing, elasticSearchEntityRepositoryDetail);
        if (CollectionUtils.isEmpty(searchHits)) return Optional.empty();
        if (searchHits.size() != 1) throw new GlobalSystemException("根据查询条件得到{}条数据", searchHits.size());
        List<R> rs = elasticSearchEntityRepositoryDetail.parseToEntity(searchHits, q.getClass());
        return Optional.ofNullable(rs.get(0));
    }

    @Override
    default <Q, R> List<R> findAll(Q q) {
        ElasticSearchEntityRepositoryDetail elasticSearchEntityRepositoryDetail = entityRepositoryDetail();
        String routing = elasticSearchEntityRepositoryDetail.routing(q);
        List<SearchHit> searchHits = elasticSearchRestTemplate().search(new Object[]{q}, routing, elasticSearchEntityRepositoryDetail);
        return elasticSearchEntityRepositoryDetail.parseToEntity(searchHits, q.getClass());
    }

    @Override
    default <Q, R> PageResponse<R> findForPage(Q q, PageRequest pageRequest) {
        ElasticSearchEntityRepositoryDetail elasticSearchEntityRepositoryDetail = entityRepositoryDetail();
        String routing = elasticSearchEntityRepositoryDetail.routing(q);
        PageResponse<SearchHit> pageResponse =
                elasticSearchRestTemplate().searchWithPage(new Object[]{q}, routing, elasticSearchEntityRepositoryDetail, pageRequest);
        List<R> rs = elasticSearchEntityRepositoryDetail.parseToEntity(pageResponse.getData(), q.getClass());
        return new PageResponse<>(pageResponse.getSearchAfter(), pageResponse.getTotal(), pageResponse.getRelation(), rs);
    }
}
